//  Abstract:
//    See gopsed-mainwindow.h
//
//  Reference:
//    See gopsed-mainwindow.h
//
//  Design Notes:
//    See gopsed-mainwindow.h
//
//  Disclaimer:
//    Copyright (C) 2008, Janice Law <janicel700@gmail.com>.
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
#include <libglademm.h>
#include <gtkmm.h>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/tuple/tuple.hpp>
#include "gopsed-mainwindow.h"
#include "gopsed-detailwindow.h"
#include "ocf.h"
#include "opf.h"

using namespace std;
using namespace boost;
using Glib::ustring;
using Glib::RefPtr;

namespace gopsed
{
MainWindow::MainWindow(BaseObjectType* base_object,
        const RefPtr<Gnome::Glade::Xml>& glade_xml) :
    Gtk::Window(base_object)
{
    glade = glade_xml;
    epub_archive = shared_ptr<Epub::Ocf>(new Epub::Ocf);
    opf_obj = shared_ptr<Epub::Opf>(new Epub::Opf);

    // Connect menu items
    Gtk::MenuItem* menuItem;
    glade->get_widget("quit1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_quit));
    glade->get_widget("new1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_new));
    glade->get_widget("open1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_open));
    glade->get_widget("save_as1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_save_as));
    glade->get_widget("cut1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_cut));
    glade->get_widget("copy1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_copy));
    glade->get_widget("paste1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_paste));
    glade->get_widget("delete1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_delete));
    glade->get_widget("about1", menuItem);
    menuItem->signal_activate().connect(sigc::mem_fun(*this, &MainWindow::on_about));

    // Connect popup buttons
    Gtk::Button* buttonItem;
    glade->get_widget("buttonTitle", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_title));
    glade->get_widget("buttonLanguage", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_language));
    glade->get_widget("buttonIdentifier", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_identifier));
    glade->get_widget("buttonCreator", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_creator));
    glade->get_widget("buttonSubject", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_subject));
    glade->get_widget("buttonDescription", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_description));
    glade->get_widget("buttonPublisher", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_publisher));
    glade->get_widget("buttonContributor", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_contributor));
    glade->get_widget("buttonDate", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_date));
    glade->get_widget("buttonType", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_type));
    glade->get_widget("buttonFormat", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_format));
    glade->get_widget("buttonSource", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_source));
    glade->get_widget("buttonRelation", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_relation));
    glade->get_widget("buttonCoverage", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_coverage));
    glade->get_widget("buttonRights", buttonItem);
    buttonItem->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::on_button_rights));

    Gtk::FileChooserDialog* file_dialog;
    glade->get_widget("filechooserdialog1", file_dialog);
    Gtk::FileFilter filter_epub;
    filter_epub.set_name("Epub files");
    filter_epub.add_pattern("*.epub");
    file_dialog->add_filter(filter_epub);

    MainWindow::RefreshData();
}

void MainWindow::LoadFile(const ustring fileName)
{
    epub_archive = shared_ptr<Epub::Ocf>(new Epub::Ocf(fileName));
    opf_obj = epub_archive->ReadOPF();
    MainWindow::RefreshData();
}

void MainWindow::on_quit()
{
    Gtk::Main::quit();
}

void MainWindow::on_about()
{
    Gtk::AboutDialog* about_dialog;
    glade->get_widget("aboutdialog1", about_dialog);
    about_dialog->set_name("OPS Editor"); // Override executable name
    about_dialog->run();
    about_dialog->hide();
}

void MainWindow::on_new()
{
    epub_archive = shared_ptr<Epub::Ocf>(new Epub::Ocf);
    opf_obj = shared_ptr<Epub::Opf>(new Epub::Opf);
    MainWindow::RefreshData();
}

void MainWindow::on_open()
{
    Gtk::FileChooserDialog* file_dialog;
    glade->get_widget("filechooserdialog1", file_dialog);
    int result = file_dialog->run();
    file_dialog->hide();
    if (result == Gtk::RESPONSE_OK)
    {
        MainWindow::LoadFile(file_dialog->get_filename());
    }
}

void MainWindow::on_save()
{
    if (epub_archive->get_archive_path().empty())
    {
        MainWindow::on_save_as();
    }
    else
    {
        MainWindow::UpdateData();
        epub_archive->WriteOPF(opf_obj);
    }
}

void MainWindow::on_save_as()
{
    // TODO: Enable after epub create is working
    Gtk::FileChooserDialog* file_dialog;
    glade->get_widget("filechooserdialog1", file_dialog);
    int result = file_dialog->run();
    file_dialog->hide();
    if (result == Gtk::RESPONSE_OK)
    {
        epub_archive = shared_ptr<Epub::Ocf>(new Epub::Ocf(file_dialog->get_filename()));
        MainWindow::UpdateData();
        epub_archive->WriteOPF(opf_obj);
    }
}

void MainWindow::on_cut()
{
    Gtk::Window* mainWindow;
    glade->get_widget("window1", mainWindow);
    Gtk::Widget* current_widget = mainWindow->get_focus();
    if (typeid(*current_widget) == typeid(Gtk::Entry))
    {
        dynamic_cast<Gtk::Entry*>(current_widget)->cut_clipboard();
    }
}

void MainWindow::on_copy()
{
    Gtk::Window* mainWindow;
    glade->get_widget("window1", mainWindow);
    Gtk::Widget* current_widget = mainWindow->get_focus();
    if (typeid(*current_widget) == typeid(Gtk::Entry))
    {
        dynamic_cast<Gtk::Entry*>(current_widget)->copy_clipboard();
    }
}

void MainWindow::on_paste()
{
    Gtk::Window* mainWindow;
    glade->get_widget("window1", mainWindow);
    Gtk::Widget* current_widget = mainWindow->get_focus();
    if (typeid(*current_widget) == typeid(Gtk::Entry))
    {
        dynamic_cast<Gtk::Entry*>(current_widget)->paste_clipboard();
    }
}

void MainWindow::on_delete()
{
    Gtk::Window* mainWindow;
    glade->get_widget("window1", mainWindow);
    Gtk::Widget* current_widget = mainWindow->get_focus();
    if (typeid(*current_widget) == typeid(Gtk::Entry))
    {
        dynamic_cast<Gtk::Entry*>(current_widget)->delete_selection();
    }
}

void MainWindow::on_button_title()
{
    opf_obj->set_title(MainWindow::UpdateLine("entryTitle",
            opf_obj->get_title()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_title(detail_window->show(opf_obj->get_title()));
    MainWindow::RefreshLine("entryTitle", opf_obj->get_title());
}

void MainWindow::on_button_language()
{
    opf_obj->set_language(MainWindow::UpdateLine("entryLanguage",
            opf_obj->get_language()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_language(detail_window->show(opf_obj->get_language()));
    MainWindow::RefreshLine("entryLanguage", opf_obj->get_language());
}

void MainWindow::on_button_identifier()
{
    opf_obj->set_identifier(MainWindow::UpdateLine("entryIdentifier",
            opf_obj->get_identifier()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_identifier(detail_window->show("id", "scheme", opf_obj->get_identifier()));
    MainWindow::RefreshLine("entryIdentifier", opf_obj->get_identifier());
}

void MainWindow::on_button_creator()
{
    opf_obj->set_creator(MainWindow::UpdateLine("entryCreator",
            opf_obj->get_creator()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_creator(detail_window->show("file-as", "role", opf_obj->get_creator()));
    MainWindow::RefreshLine("entryCreator", opf_obj->get_creator());
}

void MainWindow::on_button_subject()
{
    opf_obj->set_subject(MainWindow::UpdateLine("entrySubject",
            opf_obj->get_subject()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_subject(detail_window->show(opf_obj->get_subject()));
    MainWindow::RefreshLine("entrySubject", opf_obj->get_subject());
}

void MainWindow::on_button_description()
{
    opf_obj->set_description(MainWindow::UpdateLine("entryDescription",
            opf_obj->get_description()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_description(detail_window->show(opf_obj->get_description()));
    MainWindow::RefreshLine("entryDescription", opf_obj->get_description());
}

void MainWindow::on_button_publisher()
{
    opf_obj->set_publisher(MainWindow::UpdateLine("entryPublisher",
            opf_obj->get_publisher()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_publisher(detail_window->show(opf_obj->get_publisher()));
    MainWindow::RefreshLine("entryPublisher", opf_obj->get_publisher());
}

void MainWindow::on_button_contributor()
{
    opf_obj->set_contributor(MainWindow::UpdateLine("entryContributor",
            opf_obj->get_contributor()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_contributor(detail_window->show("file-as", "role", opf_obj->get_contributor()));
    MainWindow::RefreshLine("entryContributor", opf_obj->get_contributor());
}

void MainWindow::on_button_date()
{
    opf_obj->set_date(MainWindow::UpdateLine("entryDate",
            opf_obj->get_date()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_date(detail_window->show("event", opf_obj->get_date()));
    MainWindow::RefreshLine("entryDate", opf_obj->get_date());
}

void MainWindow::on_button_type()
{
    opf_obj->set_type(MainWindow::UpdateLine("entryType",
            opf_obj->get_type()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_type(detail_window->show(opf_obj->get_type()));
    MainWindow::RefreshLine("entryType", opf_obj->get_type());
}

void MainWindow::on_button_format()
{
    opf_obj->set_format(MainWindow::UpdateLine("entryFormat",
            opf_obj->get_format()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_format(detail_window->show(opf_obj->get_format()));
    MainWindow::RefreshLine("entryFormat", opf_obj->get_format());
}

void MainWindow::on_button_source()
{
    opf_obj->set_source(MainWindow::UpdateLine("entrySource",
            opf_obj->get_source()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_source(detail_window->show(opf_obj->get_source()));
    MainWindow::RefreshLine("entrySource", opf_obj->get_source());
}

void MainWindow::on_button_relation()
{
    opf_obj->set_relation(MainWindow::UpdateLine("entryRelation",
            opf_obj->get_relation()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_relation(detail_window->show(opf_obj->get_relation()));
    MainWindow::RefreshLine("entryRelation", opf_obj->get_relation());
}

void MainWindow::on_button_coverage()
{
    opf_obj->set_coverage(MainWindow::UpdateLine("entryCoverage",
            opf_obj->get_coverage()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_coverage(detail_window->show(opf_obj->get_coverage()));
    MainWindow::RefreshLine("entryCoverage", opf_obj->get_coverage());
}

void MainWindow::on_button_rights()
{
    opf_obj->set_rights(MainWindow::UpdateLine("entryRights",
            opf_obj->get_rights()));
    scoped_ptr<DetailWindow> detail_window(new DetailWindow(glade));
    opf_obj->set_rights(detail_window->show(opf_obj->get_rights()));
    MainWindow::RefreshLine("entryRights", opf_obj->get_rights());
}

void MainWindow::RefreshLine(ustring widgetName,
        Epub::Opf::ustring_1_list widgetData)
{
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    widgetData.empty() ? entry->set_text("")
            : entry->set_text(widgetData.front().get<0>());
}

void MainWindow::RefreshLine(ustring widgetName,
        Epub::Opf::ustring_2_list widgetData)
{
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    widgetData.empty() ? entry->set_text("")
            : entry->set_text(widgetData.front().get<0>());
}

void MainWindow::RefreshLine(ustring widgetName,
        Epub::Opf::ustring_3_list widgetData)
{
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    widgetData.empty() ? entry->set_text("")
            : entry->set_text(widgetData.front().get<0>());
}

void MainWindow::RefreshData()
{
    MainWindow::RefreshLine("entryTitle", opf_obj->get_title());
    MainWindow::RefreshLine("entryLanguage", opf_obj->get_language());
    MainWindow::RefreshLine("entryIdentifier", opf_obj->get_identifier());
    MainWindow::RefreshLine("entryCreator", opf_obj->get_creator());
    MainWindow::RefreshLine("entrySubject", opf_obj->get_subject());
    MainWindow::RefreshLine("entryDescription", opf_obj->get_description());
    MainWindow::RefreshLine("entryPublisher", opf_obj->get_publisher());
    MainWindow::RefreshLine("entryContributor", opf_obj->get_contributor());
    MainWindow::RefreshLine("entryDate", opf_obj->get_date());
    MainWindow::RefreshLine("entryType", opf_obj->get_type());
    MainWindow::RefreshLine("entryFormat", opf_obj->get_format());
    MainWindow::RefreshLine("entrySource", opf_obj->get_source());
    MainWindow::RefreshLine("entryRelation", opf_obj->get_relation());
    MainWindow::RefreshLine("entryCoverage", opf_obj->get_coverage());
    MainWindow::RefreshLine("entryRights", opf_obj->get_rights());
}

Epub::Opf::ustring_1_list MainWindow::UpdateLine(ustring widgetName,
        Epub::Opf::ustring_1_list widgetData)
{
    Epub::Opf::ustring_1_list result = widgetData;
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    Epub::Opf::ustring_1_entry new_entry;
    if (!widgetData.empty())
    {
        new_entry = widgetData.front();
        result.pop_front();
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    else if (!entry->get_text().empty())
    {
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    return result;
}

Epub::Opf::ustring_2_list MainWindow::UpdateLine(ustring widgetName,
        Epub::Opf::ustring_2_list widgetData)
{
    Epub::Opf::ustring_2_list result = widgetData;
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    Epub::Opf::ustring_2_entry new_entry;
    if (!widgetData.empty())
    {
        new_entry = widgetData.front();
        result.pop_front();
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    else if (!entry->get_text().empty())
    {
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    return result;
}

Epub::Opf::ustring_3_list MainWindow::UpdateLine(ustring widgetName,
        Epub::Opf::ustring_3_list widgetData)
{
    Epub::Opf::ustring_3_list result = widgetData;
    Gtk::Entry* entry;
    glade->get_widget(widgetName, entry);
    Epub::Opf::ustring_3_entry new_entry;
    if (!widgetData.empty())
    {
        new_entry = widgetData.front();
        result.pop_front();
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    else if (!entry->get_text().empty())
    {
        new_entry.get<0>() = entry->get_text();
        result.push_front(new_entry);
    }
    return result;
}

void MainWindow::UpdateData()
{
    opf_obj->set_title(MainWindow::UpdateLine("entryTitle",
            opf_obj->get_title()));
    opf_obj->set_language(MainWindow::UpdateLine("entryLanguage",
            opf_obj->get_language()));
    opf_obj->set_identifier(MainWindow::UpdateLine("entryIdentifier",
            opf_obj->get_identifier()));
    opf_obj->set_creator(MainWindow::UpdateLine("entryCreator",
            opf_obj->get_creator()));
    opf_obj->set_subject(MainWindow::UpdateLine("entrySubject",
            opf_obj->get_subject()));
    opf_obj->set_description(MainWindow::UpdateLine("entryDescription",
            opf_obj->get_description()));
    opf_obj->set_publisher(MainWindow::UpdateLine("entryPublisher",
            opf_obj->get_publisher()));
    opf_obj->set_contributor(MainWindow::UpdateLine("entryContributor",
            opf_obj->get_contributor()));
    opf_obj->set_date(MainWindow::UpdateLine("entryDate", opf_obj->get_date()));
    opf_obj->set_type(MainWindow::UpdateLine("entryType", opf_obj->get_type()));
    opf_obj->set_format(MainWindow::UpdateLine("entryFormat",
            opf_obj->get_format()));
    opf_obj->set_source(MainWindow::UpdateLine("entrySource",
            opf_obj->get_source()));
    opf_obj->set_relation(MainWindow::UpdateLine("entryRelation",
            opf_obj->get_relation()));
    opf_obj->set_coverage(MainWindow::UpdateLine("entryCoverage",
            opf_obj->get_coverage()));
    opf_obj->set_rights(MainWindow::UpdateLine("entryRights",
            opf_obj->get_rights()));
}
} // gopsed
